# -*- coding: utf-8 -*-
# http://python.org/dev/peps/pep-0263/
# 引入公共程序，必须放在引用其他自定义文件之前（修正引用资源路径等）
import binascii
import os
from utils.common import commonProgram
import importlib
import re
from utils.strHandlers import FirstLetterToLower, FirstLetterToUpper

import random
import sys
import time
from PySide6.QtCore import Signal, QTimer, QDateTime, Qt, QObject, Slot, QThread
from PySide6.QtGui import QFont, QTextCharFormat, QColor, QTextCursor, QShortcut, QKeySequence
from PySide6.QtWidgets import QMainWindow, QMessageBox, QFileDialog, QApplication, QTableWidgetItem, QRadioButton

from main_ui import Ui_MainWindow
from loguru import logger

from utils.strTools import extract_window_classes
from windowUI import *


class MainWindow(QMainWindow, Ui_MainWindow):
    # 声明带一个字典类型参数的信号
    mainSignal = Signal(dict)  # 主界面的信号用来绑定子界面类的函数方法
    # UI打印内容时，需要显示在 QStatusBar 的信息类型
    showInStatusBar = ['status_serial', 'status_show', 'status_ft4222']

    def __init__(self):
        super().__init__()
        # 引入配置文件
        self.myConfig = commonProgram.EnableConfigHandler()
        print('MainWindow get config Version', self.myConfig.version)
        # 启动UI
        self.setupUi(self)
        self.setWindowTitle(f"{self.myConfig.appname} -- {self.myConfig.version}")
        # 连接 信号 与 槽
        self.SignalConnectInit()
        # 定时器初始化
        self.TimerInit()
        # 添加快捷键
        self.ShortcutFun()
        # self.setWindowOpacity(0.7)  # 设置透明度
        # 引入可控设备信息窗口
        self.ft4222Win = commonProgram.EnableFt4222(winSignal=self.mainSignal, RecvFt4222Data=self.RecvFt4222Data)
        # time.sleep(2)
        # self.ft4222Win.show()
        self.actionFt4222.trigger()
        # 启用默认插件
        self.EnableDefaultPlugins()
        # 加载默认插件
        self.LoadDefaultPlugins()
        # 加载外部插件
        self.InitExternalPlugins()

    def TimerInit(self):
        """
        定时器创建与信号连接
        :return:
        """
        self.timer_send = QTimer()
        self.timer_send.timeout.connect(self.HandSendFun)
        self.timer_read = QTimer()
        self.timer_read.timeout.connect(self.HandReadFun)

    def SignalConnectInit(self):
        """
        连接来自UI对象的信号与槽
        :return:
        """
        # QPushButton
        self.btnHandSend.clicked.connect(self.HandSendFun)
        self.btnHandRead.clicked.connect(self.HandReadFun)
        # menubar
        self.actionHelp.triggered.connect(self.OpenHelpWin)
        # toolbar action
        self.actionSaveLog.triggered.connect(self.SaveLogs)
        self.actionFullScreen.triggered.connect(self.WindowSizeFun)
        self.actionUnfoldAndFold.triggered.connect(self.UnfoldAndFoldFun)
        # Serial Port action
        self.actionFt4222.triggered.connect(self.CtrlFt4222Window)
        self.checkBoxTimerSend.stateChanged.connect(self.TimerSendFun)
        self.checkBoxTimerRead.stateChanged.connect(self.TimerReadFun)
        # QAction
        self.actionAddAction.triggered.connect(self.actionAddActionFun)

    def EnableDefaultPlugins(self):
        # 默认插件1--> IICBatchProcessWindow
        self.radioIICBatchProcessWindow = QRadioButton(self.tabPlugIn)
        self.radioIICBatchProcessWindow.setObjectName("windowUI__" + IICBatchProcessWindow.__name__)
        try:
            radio_title = IICBatchProcessWindow().__doc__.strip().splitlines()[0]
            self.radioIICBatchProcessWindow.setText(radio_title) if len(radio_title) > 0 else None
        except Exception as err:
            logger.error(err)
            self.radioIICBatchProcessWindow.setText(IICBatchProcessWindow.__name__)
        self.verticalLayout_5.addWidget(self.radioIICBatchProcessWindow)
        self.radioIICBatchProcessWindow.clicked.connect(self.RadioClickedFun)
        ###################################################################################
        # 默认插件2--> ChecksumWindow
        self.radioChecksumWindow = QRadioButton(self.tabPlugIn)
        self.radioChecksumWindow.setObjectName("windowUI__" + ChecksumWindow.__name__)
        try:
            radio_title = ChecksumWindow().__doc__.strip().splitlines()[0]
            self.radioChecksumWindow.setText(radio_title) if len(radio_title) > 0 else None
        except Exception as err:
            logger.error(err)
            self.radioChecksumWindow.setText(ChecksumWindow.__name__)
        self.verticalLayout_5.addWidget(self.radioChecksumWindow)
        self.radioChecksumWindow.clicked.connect(self.RadioClickedFun)
        ###################################################################################
        # 默认插件3--> IICDtcParseWindow
        self.radioIICDtcParseWindow = QRadioButton(self.tabPlugIn)
        self.radioIICDtcParseWindow.setObjectName("windowUI__" + IICDtcParseWindow.__name__)
        try:
            radio_title = IICDtcParseWindow().__doc__.strip().splitlines()[0]
            self.radioIICDtcParseWindow.setText(radio_title) if len(radio_title) > 0 else None
        except Exception as err:
            logger.error(err)
            self.radioIICDtcParseWindow.setText(IICDtcParseWindow.__name__)
        self.verticalLayout_5.addWidget(self.radioIICDtcParseWindow)
        self.radioIICDtcParseWindow.clicked.connect(self.RadioClickedFun)
        ###################################################################################

    def InsertPlugToUi(self, className: str, package: str):
        selected_module = importlib.import_module(f".{FirstLetterToLower(className)}", package=package)
        selected_module = importlib.reload(selected_module)
        expr = f"self.radio{className} = QRadioButton(self.tabPlugIn)"
        exec(expr)
        expr = f"self.radio{className}.setObjectName('{package}__{className}')"
        exec(expr)
        try:
            expr = f"self.radio_title = selected_module.{className}().__doc__.strip().splitlines()[0]"
            exec(expr)
            expr = f"self.radio{className}.setText(self.radio_title) if len(self.radio_title) > 0 else None"
            exec(expr)
        except Exception as err:
            logger.error(err)
            expr = f"self.radio{className}.setText(selected_module.{className}.__name__)"
            exec(expr)
        expr = f"self.verticalLayout_5.addWidget(self.radio{className})"
        exec(expr)
        expr = f"self.radio{className}.clicked.connect(self.RadioClickedFun)"
        exec(expr)

    def LoadDefaultPlugins(self):
        try:
            # 指定包名和 __init__.py 文件路径
            file_path = 'windowUI/__init__.py'
            # 从 __init__.py 文件中提取模块名和类名
            matches = extract_window_classes(file_path)
            if len(matches) <= 0:
                print('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
                print('X- There are no default modules. -X')
                print('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
                return
            for module_name, class_name in matches:
                print(f"Module: {module_name}, windowUI: {class_name}")
                # 动态导入模块
                # selected_module = importlib.import_module(f".{module_name}", package='windowUI')
                # selected_module = importlib.reload(selected_module)
                # 获取类对象
                # cls = getattr(selected_module, class_name)
                # 创建类实例
                # instance = cls()
                # # 使用类实例（例如调用方法）
                # if hasattr(instance, 'show'):
                #     instance.show()
                # else:
                #     print(f"{class_name} instance created successfully")
                self.InsertPlugToUi(class_name, "windowUI")
        except Exception as err:
            logger.error(err)

    def InitExternalPlugins(self):
        try:
            # 从 __init__.py 文件中提取模块名和类名
            matches = extract_window_classes(self.myConfig.pluginDir + '/__plugins__.py')
            if len(matches) <= 0:
                print('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
                print('X- There are no external modules. Please confirm the configuration file -X')
                print('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
                return
            # 获取目录中的所有文件
            for filename in os.listdir(self.myConfig.pluginDir):
                # 加载其他所有py文件，除了__init__.py
                if filename == "__plugins__.py" or not filename.endswith(".py"):
                    continue
                try:
                    selected_module = importlib.import_module(f"plugins.{filename[:-3]}")
                    selected_module = importlib.reload(selected_module)
                except Exception as err:
                    logger.error(f"Error loading module {filename}: {err}")
            # 展示插件
            for module_name, class_name in matches:
                self.InsertPlugToUi(class_name, "plugins")
                print(f"Module: {module_name}, {self.myConfig.pluginDir}: {class_name}")
        except Exception as err:
            logger.exception(err)

    def RadioClickedFun(self):
        # 获取发送信号的 QAction
        sender = self.sender()
        object_name = sender.objectName()
        object_text = sender.text()
        # print(object_name, object_text)
        # 使用正则表达式查找
        # objPrefix = re.findall(r'radio(\w+)', object_name)
        # 使用正则表达式匹配第一个 '__' 前后的内容
        match = re.match(r'([^_]+)__(.+)', object_name)
        package_name = match.group(1)
        class_name = match.group(2)
        # print(objPrefix[0])
        # 可以同时开启多个插件窗口
        suffix = binascii.hexlify(os.urandom(3)).decode('utf-8')
        # selected_module = importlib.import_module(f".{FirstLetterToLower(objPrefix[0])}", package='windowUI')
        # selected_module = importlib.reload(selected_module)
        if package_name == "windowUI":
            try:
                selected_module = importlib.import_module("windowUI")
                selected_module = importlib.reload(selected_module)
                expr = f"self.curItemWin{suffix} = selected_module.{FirstLetterToUpper(class_name)}()"
                exec(expr)
            except Exception as err:
                logger.error(err)
        else:
            try:
                selected_module = importlib.import_module(f"plugins.{FirstLetterToLower(class_name)}")
                selected_module = importlib.reload(selected_module)
                expr = f"self.curItemWin{suffix} = selected_module.{FirstLetterToUpper(class_name)}()"
                exec(expr)
            except Exception as err:
                logger.error(err)
        # 设置窗口名
        expr = f"self.curItemWin{suffix}.setWindowTitle('{self.myConfig.appname} --- {object_text}')"
        exec(expr)
        # 显示窗口
        expr = f"self.curItemWin{suffix}.show()"
        exec(expr)

    def SendDataHandle(self, dataDict: dict):
        """
        发送信号或数据处理函数
        :param dataDict:
        :return:
        """
        # 发送信号处理
        dataObj = dataDict.get('data', '')
        typeValue = dataDict.get('type', 'null').strip()
        # 本窗口发送数据
        if "send_" in typeValue:
            self.mainSignal.emit(dataDict)
        elif "read_" in typeValue:
            self.mainSignal.emit(dataDict)
        elif 'Main_to_' in typeValue:
            # logger.info("Main窗口发往其他窗口的数据：", typeValue, dataObj)
            self.mainSignal.emit(dataDict)
        elif typeValue != None:
            self.UIPrintFun(strData=dataObj, typeValue=typeValue)
        # do something

    def RecvFt4222Data(self, dictData: dict):
        """
        用于接收串口控制窗口发过来的信号或数据
        :param dictData:
        :return:
        """
        try:
            self.RecvDataHandle(dictData)
        except Exception as err:
            msg = str(err)
            logger.exception(msg)
            self.UIPrintFun(strData=msg, typeValue='status_show')

    def RecvDataHandle(self, dataDict: dict):
        """
        处理串口控制窗口发过来的信号或数据
        :param dataDict:
        :return:
        """
        typeValue = dataDict.get("type", '').strip()
        dataObj = dataDict.get('data', {})
        optionsDict = dataDict.get('options', {})
        # 收到信号
        if 'Main_to_' in typeValue:
            return
        if "_to_Main_call_ScriptProcessFun" in typeValue:
            self.ScriptProcessFun(dataObj)
            return
        if typeValue == 'status_ft4222':
            if dataObj == "Ft4222_Window_Showed":
                self.CtrlFt4222Window(True)
            elif dataObj == "Ft4222_Window_Closed":
                self.CtrlFt4222Window(False)
        elif typeValue == 'rece_protobuf':
            pass
        elif typeValue == 'read_hex':
            # 使用hexlify函数将bytes数据转换为16进制字符串
            hex_string = binascii.hexlify(dataObj).decode('utf-8').upper()
            # 插入空格
            dataObj = ' '.join(hex_string[i:i + 2] for i in range(0, len(hex_string), 2))
        elif typeValue == 'rece_ascii':
            pass
        elif '_to_Main' in typeValue:
            logger.info("收到其他窗口发往Main窗口的数据：", typeValue, dataObj)
        elif 'send_' in typeValue:
            raw_data = optionsDict.get('raw_data', '').strip()
            if len(raw_data) > 0:
                dataObj = f"{dataObj} <-- {raw_data}"
        # 其他情况
        if ('_' not in typeValue) and (typeValue != None):
            pass
        if self.checkBoxExpectData.isChecked():
            expectData = optionsDict.get('expectData', '').strip()
            if (len(expectData) > 0) and (str(expectData) not in str(dataObj)):
                self.UIPrintFun(strData=dataObj, typeValue=typeValue, statusOk=False)
                self.UIPrintFun(strData=expectData, typeValue="expectData", statusOk=False)
                return
        # do something
        self.UIPrintFun(strData=dataObj, typeValue=typeValue)

    def UIPrintFun(self, strData, timeStr=None, typeValue=None, statusOk=True):
        '''
        界面 textBrowser 显示内容
        '''
        # # 通过 mainSignal 向界面传递数据
        # self.mainSignal.emit({"data": dataObj, "type": typeValue})
        # data = "AA BB CC DD EE FF "
        # 获取当前时间并格式化
        # current_time = None
        if (not timeStr) and self.checkBoxTimestamp.isChecked():
            timeStr = QDateTime.currentDateTime().toString(self.lineEditTimeFormat.text().strip())
        status = None
        if self.checkBoxDatatype.isChecked():
            status = typeValue
        endOfLine = None
        if self.checkBoxEndOfLine.isChecked():
            endOfLine = self.lineEditEndOfLine.text().strip().encode().decode('unicode_escape')

        # 创建一个 QTextCharFormat 用于设置文本格式
        time_format = QTextCharFormat()
        time_format.setForeground(QColor(0, 0, 255, 255))  # 设置时间文本颜色为蓝色

        status_format = QTextCharFormat()
        status_format.setForeground(QColor(0, 255, 33, 255))  # 设置状态文本颜色为绿色
        if not statusOk:
            status_format.setForeground(QColor(255, 0, 0, 255))

        text_format = QTextCharFormat()
        text_format.setForeground(QColor(0, 0, 0, 255))  # 设置文字说明文本颜色为黑色

        # 需要显示在 QStatusBar 的信息类型
        if typeValue in self.showInStatusBar:
            self.statusbar.showMessage(strData)
            status_format.setForeground(QColor(128, 128, 128, 255))

        # 在 QTextBrowser 中插入格式化的文本
        cursor = self.textBrowser.textCursor()
        # 插入时间文本并应用格式
        cursor.insertText(timeStr, time_format)
        # 插入状态文本并应用格式
        if status:
            cursor.insertText(" " + status + " ", status_format)
        # 插入文字说明文本并应用格式
        cursor.insertText(str(strData), text_format)
        # 换行
        cursor.insertText(endOfLine)
        # 将光标移动到文本末尾
        cursor.movePosition(QTextCursor.End)
        self.textBrowser.setTextCursor(cursor)

    def actionAddActionFun(self):
        pass

    def ShortcutFun(self):
        """
        快捷键 F11 全屏
        快捷键 F5 清屏
        :return:
        """
        # 快捷键 F11
        self.screenStatus = 'Normal'
        # 创建快捷键，已 通过UI 绑定
        # self.screenShortcut = QShortcut(QKeySequence(Qt.Key_F11), self)
        # self.screenShortcut.activated.connect(self.WindowSizeFun)
        self.setToolTip('全屏与退出全屏：\n               双击 或者 F11')
        # 快捷键 F5
        # screenShortcut2 = QShortcut(QKeySequence(Qt.Key_F5), self)
        # screenShortcut2.activated.connect(self.CleanFun)

    def WindowSizeFun(self):
        """
        控制窗口尺寸，此处为原大小（最小UI布局）或者全屏
        :return:
        """
        if self.screenStatus == 'Normal':
            self.showFullScreen()
            self.screenStatus = 'FullScreen'
        else:
            self.showNormal()
            self.screenStatus = 'Normal'

    def UnfoldAndFoldFun(self):
        if "收起" in self.actionUnfoldAndFold.text():
            self.actionUnfoldAndFold.setText("展开")
            self.toolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextOnly)
        elif "展开" in self.actionUnfoldAndFold.text():
            self.actionUnfoldAndFold.setText("收起")
            self.toolBar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextUnderIcon)

    def HandSendFun(self):
        slaveAddr = self.lineEditWriteSlaveAddr.displayText().strip().upper()
        if (len(slaveAddr) < 1) or ("0X" not in slaveAddr):
            QMessageBox.warning(self, "空数据", f"请输入正确的设备地址！--> {slaveAddr}")
            return None
        send_data = self.plainTextEditSendData.toPlainText().strip().upper().replace('0X', '')
        if len(send_data) < 1:
            QMessageBox.warning(self, "空数据", f"请输入要发送的内容！--> {send_data}")
            return None
        # if self.checkRemoveStr.isChecked():
        #     dataStr = eval(dataStr)
        # hex发送
        input_s = send_data
        send_list = []
        while input_s != '':
            try:
                num = int(input_s[0:2], 16)
            except ValueError:
                # QMessageBox.critical(self, 'wrong data', '请输入十六进制数据，以空格分开!')
                return None
            input_s = input_s[2:].strip()
            send_list.append(num)
        input_s = bytes(send_list)
        i2cData = {
            "slaveAddr": eval(slaveAddr),
            "writeData": input_s,
        }
        dictData = {"data": i2cData, "type": f"send_{self.comboBoxSendDataType.currentText().strip()}",
                    "options": {"msg_id": int(self.spinBoxMessageId.value()), "raw_data": send_data}}
        self.SendDataHandle(dictData)

    def HandReadFun(self):
        slaveAddr = self.lineEditReadSlaveAddr.displayText().strip().upper()
        if (len(slaveAddr.strip()) < 3) or ("0X" not in slaveAddr):
            QMessageBox.warning(self, "空数据", f"请输入正确的设备地址！--> {slaveAddr}")
            return None
        dataAddr = self.lineEditDataAddr.displayText().strip().upper()
        if ("0X" in dataAddr) and (len(dataAddr.strip()) < 3):
            QMessageBox.warning(self, "空数据", f"请输入正确的数据地址！--> {dataAddr}")
            return None
        dataLen = int(self.spinBoxReadLen.value())
        if dataLen < 1:
            QMessageBox.warning(self, "空数据", f"请输入正确的读取长度！--> {dataLen}")
            return None
        expectData = self.plainTextEditExpectData.toPlainText().strip().upper().replace('0X', '')
        if (self.checkBoxExpectData.isChecked()) and (len(expectData) < 1):
            QMessageBox.warning(self, "空数据", f"请输入 期望读到的数据！或者 在打印设置中去掉勾选！--> {dataLen}")
            return None
        # print('HandReadFun', dataStr)
        # if self.checkRemoveBytes.isChecked():
        #     dataStr = str(dataStr)
        input_s = dataAddr.strip().replace('0X', '')
        send_list = []
        addrLen = 0
        while input_s != '':
            addrLen += 1
            try:
                num = int(input_s[0:2], 16)
            except ValueError:
                # QMessageBox.critical(self, 'wrong data', '请输入十六进制数据，以空格分开!')
                return None
            input_s = input_s[2:].strip()
            send_list.append(num)
        input_s = bytes(send_list)
        i2cData = {
            "slaveAddr": eval(slaveAddr),
            "dataAddr": input_s,
            "dataLen": dataLen,
        }
        dictData = {"data": i2cData, "type": f"read_{self.comboBoxReadDataType.currentText().strip().lower()}",
                    "options": {"addrLen": addrLen, "expectData": expectData,
                                "msg_id": int(self.spinBoxMessageId.value())}}
        self.SendDataHandle(dictData)

    def ScriptProcessFun(self, dictData: dict):
        self.spinBoxMessageId.setValue(int(dictData.get("msg_id", 0)))
        if "w" in dictData.get("write_read", "").lower():
            self.lineEditWriteSlaveAddr.setText(dictData.get("slaveAddr", ""))
            self.plainTextEditSendData.setPlainText(
                dictData.get("cmd_addr", "").strip() + " " + dictData.get("data_len", "").strip())
            self.comboBoxSendDataType.setCurrentText(dictData.get("dataType", "hex").strip())
            self.btnHandSend.click()
        else:
            self.lineEditReadSlaveAddr.setText(dictData.get("slaveAddr", ""))
            self.lineEditDataAddr.setText(dictData.get("cmd_addr", ""))
            self.spinBoxReadLen.setValue(int(dictData.get("data_len", 0)))
            self.comboBoxReadDataType.setCurrentText(dictData.get("dataType", "hex").strip())
            self.plainTextEditExpectData.setPlainText(dictData.get("expectData", "").strip().upper())
            self.btnHandRead.click()

    def TimerSendFun(self):
        """
        定时发送数据
        :return:
        """
        if self.checkBoxTimerSend.isChecked():
            timeDelay = int(self.spinBoxSendTime.text())
            if timeDelay < 1:
                QMessageBox.critical(self, 'wrong data', '请输入 正确的 延时 ！')
                return None
            self.timer_send.start(timeDelay)
            self.spinBoxSendTime.setEnabled(False)
        else:
            self.timer_send.stop()
            self.spinBoxSendTime.setEnabled(True)

    def TimerReadFun(self):
        """
        定时发送数据
        :return:
        """
        if self.checkBoxTimerRead.isChecked():
            timeDelay = int(self.spinBoxReadTime.text())
            if timeDelay < 1:
                QMessageBox.critical(self, 'wrong data', '请输入 正确的 延时 ！')
                return None
            self.timer_read.start(timeDelay)
            self.spinBoxReadTime.setEnabled(False)
        else:
            self.timer_read.stop()
            self.spinBoxReadTime.setEnabled(True)

    def OpenHelpWin(self):
        self.helpWindow = HelpWindow()
        self.helpWindow.show()

    def CtrlFt4222Window(self, triggered):
        """
        控制串口控制窗口
        :param triggered:
        :return:
        """
        if triggered:
            self.actionFt4222.setChecked(True)
            self.ft4222Win.show()
        else:
            self.actionFt4222.setChecked(False)
            self.ft4222Win.close()

    def SaveLogs(self):
        try:
            StrText = self.textBrowser.toPlainText()
            textStr = str(StrText)
            # 前面是地址，后面是文件类型,得到输入地址的文件名和地址txt(*.txt*.xls);;image(*.png)不同类别
            # 对话框的父容器parent：一般选为调用对话框的窗体对象。
            # 对话框标题caption：弹出对话框的标题。
            # 文件过滤器filter：选择不同后缀的文件。
            # 初始文件过滤器initialFilter：设置初始的文件过滤器。
            # 对话框options：一个枚举类型。例如：QFileDialog.ShowDirsOnly只显示目录等。
            # 获取到的fileName和filtUsed：是两个元组类型数据。
            filepath, type = QFileDialog.getSaveFileName(self, "打印内容保存", 'data', filter='txt(*.txt)')
            file = open(filepath, 'w')
            # print(filepath, type)
            file.write(textStr)
            file.close()
        except Exception as e:
            pass

    def closeEvent(self, event):
        """
        防止误触关闭程序
        :param event:
        :return:
        """
        # 创建一个确认退出的对话框
        reply = QMessageBox.question(
            self, "Confirmation", "Are you sure you want to exit?",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No
        )
        if reply == QMessageBox.StandardButton.Yes:
            # 用户确认退出，关闭应用
            event.accept()
            sys.exit(0)  # 退出程序
        else:
            event.ignore()


# 程序入口
if __name__ == "__main__":
    app = QApplication(sys.argv)
    font = QFont("宋体")
    pointsize = font.pointSize()
    font.setPixelSize(int(pointsize * 90 / 72))
    app.setFont(font)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec())
